<template>
  <el-drawer title="Chat History" size="100%" :visible.sync="visible" direction="rtl" :before-close="onClose">
    <div class="float-export-btn" @click="exportChatHistory">
      <img :src="ExportIcon" alt="export" class="export-icon" title="export">
    </div>
    <div class="chat-history" v-loading="loading" element-loading-text="Hard Loading...">
      <el-scrollbar class="chat-history-scrollbar" ref="scrollbar" id="historyScrollbar">
        <ul>
          <li v-for="(msgInfo, idx) in messages" :key="idx">
            <chat-message-item :mode="2" :mine="msgInfo.sendId == mine.id" :headImage="headImage(msgInfo)"
                               :showName="showName(msgInfo)" :msgInfo="msgInfo" :menu="false">
            </chat-message-item>
          </li>
        </ul>
      </el-scrollbar>
    </div>
  </el-drawer>
</template>

<script>
import ChatMessageItem from './ChatMessageItem.vue';
import {MESSAGE_TYPE} from "@/api/enums";
import {CryptoUtil} from "@/api/cryptoUtil";

export default {
  name: 'chatHistory',
  components: {
    ChatMessageItem
  },
  props: {
    visible: {
      type: Boolean
    },
    chat: {
      type: Object
    },
    friend: {
      type: Object
    },
    group: {
      type: Object
    },
    groupMembers: {
      type: Array,
    }
  },
  data() {
    return {
      page: 1,
      size: 10,
      messages: [],
      loadAll: false,
      loading: false,
      lastScrollTime: new Date(),
      ExportIcon: require('../../assets/icon/exportIcon.png')
    }
  },
  methods: {
    onClose() {
      this.page = 1;
      this.messages = [];
      this.loadAll = false;
      this.$emit('close');
    },
    onScroll() {
      let high = this.$refs.scrollbar.$refs.wrap.scrollTop;
      let timeDiff = new Date().getTime() - this.lastScrollTime.getTime();
      if (high < 30 && timeDiff > 500) {
        this.lastScrollTime = new Date();
        this.loadMessages();

      }
    },
    exportChatHistory() {
      if (this.messages.length === 0) return;
      this.$prompt('Please enter the password for the zip file', {
        confirmButtonText: 'OK',
        cancelButtonText: 'Cancel',
        inputType: 'text',
        inputPattern: /\S/,
        inputErrorMessage: 'The password cannot be empty',
        customClass: 'custom-prompt-password'
      }).then(({value: password}) => {
        const msgIdArr = this.messages.map(item => item.id);
        console.log("messages", msgIdArr)

        var outputFileName = 'chats.zip'
        const getMsgs = (idArr) => {
          return new Promise((resolve, reject) => {
            this.$http({
              url: "/message/private/historyByIds",
              method: 'post',
              data: {
                ids: idArr
              }
            })
                .then((data) => {
                  console.log('data', data)
                  resolve(data)
                }).catch(reject)
          });
        }

        const process1Message = (msg) => {

          return new Promise((resolve, reject) => {
            if (msg.type == undefined ||
                ![MESSAGE_TYPE.TEXT, MESSAGE_TYPE.IMAGE, MESSAGE_TYPE.FILE,
                  MESSAGE_TYPE.AUDIO, MESSAGE_TYPE.VIDEO].includes(msg.type)) {
              resolve(null)
            }


            var msgInfo = msg
            var plainText = msgInfo.content
            var cryptoInstance;
            if (msgInfo.code) {

              cryptoInstance = this.$store.getters.cryptoInstance();
              plainText = cryptoInstance.cryptoUtil.decryptText(cryptoInstance, {
                keyEncrypted: msgInfo.sendCke,
                content: msgInfo.content
              });
              // var plain = this.dispatch("decryptText", {keyEncry: msgInfo.sendCke, content: msgInfo.content}, {root:true});
              cryptoInstance.cryptoUtil.toNotEncrypted(msgInfo, plainText)
            } else {
              console.log('else')
            }
            console.log('msgInfo', msgInfo,msg )
            if ([MESSAGE_TYPE.IMAGE, MESSAGE_TYPE.FILE,
              MESSAGE_TYPE.AUDIO, MESSAGE_TYPE.VIDEO].includes(msg.type)) {

              // load(JSON.parse(msg.content).originUrl)
              cryptoInstance = this.$store.getters.cryptoInstance();
              cryptoInstance.cryptoUtil.decryptFileReal(cryptoInstance, JSON.parse(msgInfo.content).originUrl)
                  .then(decryptedFile => {
                    msg.file = decryptedFile
                    console.log('resolve', msg)
                    resolve(msg)
                  })

            } else {
              resolve(msg)
            }

          });
        }

        const parseMsgs = (msgs) => {
          var promiseArrOfRes = []
          for (const msg of msgs) {
            promiseArrOfRes.push(process1Message(msg));
          }
          Promise.all(promiseArrOfRes).then(processMsgObjs).catch(e => {
            console.log(e)
          })
        }

        getMsgs(msgIdArr).then(parseMsgs).catch(e => {
          // getMsgs([111]).then(parseMsgs).catch(e=>{
          console.log(e)
        })

        const processMsgObjs = (msgObjs) => {
          console.log('processMsgObjs', msgObjs)
          const zip = window.zip;
          var promiseArrOfZip = []

          const model = (() => {
            let zipWriter;
            return {
              addFile(file, options) {
                if (!zipWriter) {
                  zipWriter = new zip.ZipWriter(new zip.BlobWriter("application/zip"), {bufferedWrite: true});
                }
                return zipWriter.add(file.name, new zip.BlobReader(file), options);
              },
              async getBlobURL() {
                if (zipWriter) {
                  const blobURL = URL.createObjectURL(await zipWriter.close());
                  zipWriter = null;
                  return blobURL;
                } else {
                  throw new Error("Zip file closed");
                }
              }
            };

          })();

          var signal = undefined
          for (const msgObj of msgObjs) {
            // msgobj to file
            // var file = undefined;

            var extra = false;
            var prefix = ''
            var file = new Blob([JSON.stringify(msgObj, null, 2)], {type: 'text/plain'})
            // zipTextMsg(zip, file);
            // file.name = '文本/chat-' + msgObj.id + '.json'

            // zipTextMsg(zip, file);
            console.log('zipFile', '文本/chat-' + msgObj.id + '.json')
            promiseArrOfZip.push(zipFile(model, file, '文本/chat-' + msgObj.id + '.json', signal, password))


            switch (msgObj.type) {
              case MESSAGE_TYPE.TEXT:
                // var file = new Blob([JSON.stringify(msgObj, null, 2)], {type: 'text/plain'})
                // // zipTextMsg(zip, file);
                // // file.name = '文本/chat-' + msgObj.id + '.json'
                //
                // // zipTextMsg(zip, file);
                // console.log('zipFile', '文本/chat-' + msgObj.id + '.json')
                // promiseArrOfZip.push(zipFile(model, file, '文本/chat-' + msgObj.id + '.json', signal, password))
                // // eslint-disable-next-line no-fallthrough
                break;
              case MESSAGE_TYPE.IMAGE:
                prefix = 'image/'
                extra = true
                break;
              case MESSAGE_TYPE.FILE:
                prefix = 'file/'
                extra = true
                break;
              case MESSAGE_TYPE.AUDIO:
                prefix = 'audio/'
                extra = true
                break;
              case MESSAGE_TYPE.VIDEO:
                prefix = 'video/'
                extra = true
                break;
            }
            if (extra && msgObj.file) {
              promiseArrOfZip.push(zipFile(model, msgObj.file, prefix + msgObj.file.name, signal, password))
            }

          }

          Promise.all(promiseArrOfZip).then(() => {
            console.log('all promiseArrOfZip')

            model.getBlobURL().then(blobURL => {
              console.log('blobURL', blobURL)
              if (blobURL) {
                const anchor = document.createElement("a");
                const clickEvent = new MouseEvent("click");
                anchor.href = blobURL;
                anchor.download = outputFileName;
                anchor.dispatchEvent(clickEvent);
              }
            }).catch(e => {

            })
          })
        }

        const zipFile = (model, file, fileUrl, signal, password) => {
          console.log('zipFile', file, fileUrl)

          function renameFile(originalFile, newName) {
            return new File([originalFile], newName, {
              type: originalFile.type,
              lastModified: originalFile.lastModified,
            });
          }


          return new Promise((resolve, reject) => {
            // zip.file("hello.txt", "Hello, World!\n");
            // zip.file("image.png", blob);
            // zip.file(fileUrl, blob);
            console.log('model.addFile', file, fileUrl)
            model.addFile(renameFile(file, fileUrl), {
              password,
              signal,
              onstart(max) {

              },
              onprogress(index, max) {

              }
            }).then(resolve).catch(e => {
              console.log(e);
              resolve(null)
            });
          });

        }
      }).catch(err => {
        if (err !== 'cancel') {
          this.$message.error('download failed');
        }
      });
    },
    loadMessages() {
      if (this.loadAll) {
        return this.$message.success("Reached the top");
      }
      let param = {
        page: this.page++,
        size: this.size
      }
      if (this.chat.type == 'GROUP') {
        param.groupId = this.group.id;
      } else {
        param.friendId = this.friend.id;
      }
      this.loading = true;
      this.$http({
        url: this.historyAction,
        method: 'POST',
        params: param
      }).then(messages => {
        messages.forEach(m => this.messages.unshift(m));
        this.loading = false;
        if (messages.length < this.size) {
          this.loadAll = true;
        }
        this.refreshScrollPos();
      }).catch(() => {
        this.loading = false;
      })
    },
    showName(msgInfo) {
      if (this.chat.type == 'GROUP') {
        let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
        return member ? member.remarkNickName : "";
      } else {
        return msgInfo.sendId == this.mine.id ? this.mine.nickName : this.chat.showName
      }
    },
    headImage(msgInfo) {
      if (this.chat.type == 'GROUP') {
        let member = this.groupMembers.find((m) => m.userId == msgInfo.sendId);
        return member ? member.headImage : "";
      } else {
        return msgInfo.sendId == this.mine.id ? this.mine.headImageThumb : this.chat.headImage
      }
    },
    refreshScrollPos() {
      let scrollWrap = this.$refs.scrollbar.$refs.wrap;
      let scrollHeight = scrollWrap.scrollHeight;
      let scrollTop = scrollWrap.scrollTop;
      this.$nextTick(() => {
        let offsetTop = scrollWrap.scrollHeight - scrollHeight;
        scrollWrap.scrollTop = scrollTop + offsetTop;
        // The scroll bar is not coming out. Keep loading
        if (scrollWrap.scrollHeight == scrollHeight) {
          this.loadMessages();
        }
      });
    }
  },
  computed: {
    mine() {
      return this.$store.state.userStore.userInfo;
    },
    historyAction() {
      return `/message/${this.chat.type.toLowerCase()}/history`;
    }
  },
  watch: {
    visible: {
      handler(newValue, oldValue) {
        if (newValue) {
          this.loadMessages();
          this.$nextTick(() => {
            document.getElementById('historyScrollbar').addEventListener("mousewheel", this.onScroll, true);
          });
        }
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.float-export-btn {
  position: fixed;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2001;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;

  &:hover {
    background: #f5f7fa;
    transform: translateY(-50%) scale(1.1);
    box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.2);
  }

  .export-icon {
    width: 24px;
    height: 24px;
    object-fit: contain;
  }
}

.chat-history {
  display: flex;
  width: 100%;
  height: 100%;

  .chat-history-scrollbar {
    flex: 1;

    .el-scrollbar__thumb {
      background-color: #555555;
    }

    ul {
      padding: 20px;

      li {
        list-style-type: none;
      }
    }
  }
}
</style>
